#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <pthread.h>

// 圆参数
int o_x = 100;
int o_y = 100;
int o_r = 30;
int _x = 2;
int _y = 2;

// 触碰点参数
int t_x = 0;
int t_y = 0;

// 颜色参数
int white = 0x00FFFFFF;
int o_color = 0x00000000;
int color = 0; // 写入的

struct input_event touch; // 触摸屏

void BMPInsert(int bmp_fd, int *lcd_p)
{
    // 4.读图片文件54字节
    char buffer_1[54] = {0};
    int n = read(bmp_fd, buffer_1, sizeof(buffer_1));
    if (n == 0)
    {
        perror("read bmp error");
    }

    lseek(bmp_fd, 54, SEEK_SET);

    // 5.读图片文件800*480*3字节
    char RGBbf[800 * 480 * 3] = {0};
    n = read(bmp_fd, RGBbf, sizeof(RGBbf));

    // 6.将读取出来的RGB数据转化成ARGB数据
    int ARGBbf[800 * 480] = {0};
    for (int i = 0; i < 800 * 480; i++)
    {
        ARGBbf[i] = RGBbf[3 * i] << 0 | RGBbf[3 * i + 1] << 8 | RGBbf[3 * i + 2] << 16 | 0x00 << 24;
    }

    // 7.将数据颠倒和写入
    for (int y = 0; y < 480; y++)
    {
        for (int x = 0; x < 800; x++)
        {
            *(lcd_p + x + y * 800) = ARGBbf[x + (479 - y) * 800];
        }
    }

    // 8.关闭图片文件
    close(bmp_fd);
}

int openbmp(char *name)
{
    // 2.打开图片文件
    int bmp_fd = open(name, O_RDWR);
    if (bmp_fd == -1)
    {
        perror("open lcd error");
        return -1;
    }
    return bmp_fd;
}

void *control_plank(void *arg)
{
    int *lcd_p = (int *)arg;

    // 打开触摸屏
    int ts_fd = open("/dev/input/event0", O_RDONLY);
    if (ts_fd == -1)
    {
        printf("打开触摸屏失败！\n");
    }

    int plank_color = 0x00000000;

    while (1)
    {
        read(ts_fd, &touch, sizeof(touch)); // 没触摸的时候。read是堵塞的
        if (touch.type == EV_ABS && touch.code == ABS_X)
            t_x = touch.value * 800 / 1024; // 判断是不是触摸屏设备，在判断是不是x坐标，
        if (touch.type == EV_ABS && touch.code == ABS_Y)
            t_y = touch.value * 480 / 600;
        printf("x:%d--y:%d\n", t_x, t_y); // 黑板
    }

    close(ts_fd);
}

int main()
{
    // 打开LCD文件
    int lcd_fd = open("/dev/fb0", O_RDWR);
    if (lcd_fd == -1)
        perror("open lcd error");

    // 申请内存映射
    int *lcd_p = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if (lcd_p == NULL)
        perror("mmap error");

    // 创建线程
    pthread_t td;
    pthread_create(&td, NULL, control_plank, (void *)lcd_p);

    // 圆移动
    while (1)
    {
        // 打印圆
        for (int y = 0; y < 480; y++)
        {
            for (int x = 0; x < 800; x++)
            {
                if ((x - o_x) * (x - o_x) + (y - o_y) * (y - o_y) <= o_r * o_r)
                {
                    color = o_color;
                }
                else
                {
                    color = white;
                }

                *(lcd_p + x + y * 800) = color; // 写入单像素点
            }
        }

        //打印长方形
        if (t_y - 25 > 0 && t_y + 25 < 480)
        {
            for (int y = t_y - 25; y < t_y + 25; y++)
            {
                for (int x = t_x - 50; x < t_x + 50; x++)
                {
                    *(lcd_p + x + y * 800) = o_color; // 写入单像素点
                }
            }
        }

        // 判断到边界
        if (o_x + o_r > 800 || o_x - o_r < 0)
        {
            _x = ~_x;
        }

        if (o_y - o_r < 0)
        {
            _y = ~_y;
        }

        if(o_y + o_r > 480)
        {
            int bmp_fd = openbmp("./gameover.bmp");
            BMPInsert(bmp_fd,lcd_p);
            break;
        }

        //判断触碰到长方形
        if(o_y + o_r >= t_y - 25 && (o_x >= t_x -50  && o_x <= t_x + 50))
        {
            _y = ~_y;
        }

        o_x += _x;
        o_y += _y;
    }

    // 关闭LCD文件描述符
    close(lcd_fd);

    // 释放空间
    munmap(lcd_p, 800 * 480 * 4);

    return 0;
}